var express = require('express')
    , fs = require('fs')
    , log4js = require('log4js')
    , bodyParser = require('body-parser')
    , serveStatic = require('serve-static')
    , responseTime = require('response-time')
    , morgan = require('morgan')
    , uuid_v1 = require('uuid/v1')
    // , onFinished = require('on-finished')
    , compression = require('compression')
    , mongoose = require('mongoose');

var route = require('./route');

var log4jsConf = require('./config/log4js.js');

// [WARN] log4js - Ignoring configuration reload parameter for "object" configuration.
// log4js.configure(log4jsConf, { reloadSecs: 300 });  // 貌似只有使用'xx.json' 才能使用reload，如果使用了 object 例如用的是 module.exports 的对象，就会把 reload 参数忽略掉。只有原始文件才能reload。可能检测机制是使用fs，那样就无法感知到对象的改变。
log4js.configure(log4jsConf);

var urlLog = require('./model').urlLog;

var port = 3000;
var logger = log4js.getLogger('app');

var app = module.exports = express();

app.use(compression());

app.use(function setFalseHeader(req, res, next) {
    res.setHeader('X-Powered-By', 'ASP.NET');  // 设置应用后台驱动类型   
    next();
});

app.set('trust proxy', true);  // 设置代理
// app.set('x-powered-by', false);  // 不返回系统驱动  // 或者改为虚假的

app.use(responseTime());  // 为所有的 response 添加一个记录了回复消耗时间的 x-response-time _headers字段

app.use(log4js.connectLogger(logger));
app.use(serveStatic(__dirname + '/public'));
app.use(bodyParser.urlencoded({ extended: true }));

app.use(assignId);

function assignId(req, res, next) {
    if (!req.id) {
        req.hasId = false;
        // return res.status(417).send({ code: 1, msg: 'not found id!' });  // 禁止浏览器直接访问 // 但是在这样又带来一个问题，就是没有morgan记录了
        // 甚至可以更严格的验证是否是uuid格式
        req.id = uuid_v1();
    }
    res.set('id', req.id);
    res.set('pid', process.pid);
    next();
}

var accessLogStream = fs.createWriteStream('./log/access.log', { flags: 'a' });

morgan.token('prefix', (req, res) => {
    var id = req.id;
    var pid = process.pid;
    var date = new Date();
    var dateStr = date.toLocaleString() + '.' + (date.getMilliseconds() + 1000).toString().slice(1);

    return id + ' ' + pid + ' ' + dateStr;
});

// 覆盖默认的url
morgan.token('url', (req, res) => {
    return decodeURI(req.originalUrl);
});

app.use(morgan(':prefix :remote-addr :method :url :status :res[content-length] :response-time ms'));
// app.use(morgan(':prefix :remote-addr :method :url :status :res[content-length] :response-time ms', { stream: accessLogStream }));

app.all('/*', (req, res, next) => {

    // url 日志查询的 url 日志不再添加
    if (req.path === '/log/urlLog') {
        return next();
    }

    next(); // 写入 url 日志记录之前就转到下一个 handle ，加快 response 速度

    // 判断是不是浏览器直接访问 url
    // if (!req.hasId) {
    //     return res.status(417).send({ code: 1, msg: 'not found id!' });
    // }

    let log = {
        ip: req.ip,
        referer: req.headers.referer || '-',
        url: decodeURI(req.url),
        method: req.method,
        pid: process.pid,
        host: req.header.host
    };
    new urlLog(log).save(err => {
        if (err) return console.log(err);
        // urlLog.info(req.ip + ' ' + req.method + ' ' + req.protocol + '://' + req.headers.host + decodeURI(req.url));
    });
});

// app.get('/', (req, res) => {
//     res.send('index!');
// });

route(app);

// 错误处理
app.use((err, req, res, next) => {
    if (err) {
        console.log(decodeURI(req.originalUrl), ' err: ', error.stack);
        res.status(500).send({ msg: 'Interval Server Error!' });
    }
    else {
        next();
    }
});

// 404处理
app.use((req, res, next) => {
    console.warn('找不到页面： %s', req.method + ' ' + req.headers.host + decodeURI(req.originalUrl));
    res.status(404).send('请求的页面不存在！');
});

app.listen(port, () => {
    console.log('server start! listening on %s...', port);
});